package cn.wen.yaling.aop.annotation.visit;

import cn.wen.yaling.commons.enums.EBehavior;
import cn.wen.yaling.commons.handler.RequestHolder;
import cn.wen.yaling.commons.service.RedisService;
import cn.wen.yaling.commons.utils.*;
import cn.wen.yaling.xo.dao.WebVisitDao;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 日志切面
 */
@Aspect
@Component("WebLoggerAspect")
@Slf4j
public class LoggerAspect {

    @Autowired
    ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    RedisService redisService;

    @Autowired
    WebVisitDao webVisitDao;

    @Pointcut(value = "@annotation(businessLog)")
    public void pointcut(BusinessLog businessLog) {

    }

    @Around(value = "pointcut(bussinessLog)")
    public Object doAround(ProceedingJoinPoint joinPoint, BusinessLog bussinessLog) throws Throwable {

        // 先执行业务
        Object result = joinPoint.proceed();

        try {
            // 日志收集
            handle(joinPoint);

        } catch (Exception e) {
            log.error("日志记录出错!", e);
        }

        return result;
    }

    private void handle(ProceedingJoinPoint point) throws Exception {

        HttpServletRequest request = RequestHolder.getRequest();

        Method currentMethod = AspectUtil.INSTANCE.getMethod(point);
        //获取操作名称
        BusinessLog annotation = currentMethod.getAnnotation(BusinessLog.class);

        boolean save = annotation.save();

        EBehavior behavior = annotation.behavior();

        String businessName = AspectUtil.INSTANCE.parseParams(point.getArgs(), annotation.value());

        String ua = RequestUtils.getUa();

        log.info("{} | {} - {} {} - {}", businessName, IPUtils.getIpAddr(request), RequestUtils.getMethod(), RequestUtils.getRequestUrl(), ua);
        if (!save) {
            return;
        }

        // 获取参数名称和值
        Map<String, Object> nameAndArgsMap = AopUtils.getFieldsName(point);

        Map<String, Object> result = EBehavior.getModuleAndOtherData(behavior, nameAndArgsMap, businessName);
        if (result != null) {
            Integer userId = null;
            if (request.getAttribute("userId") != null) {
                userId = Integer.parseInt(request.getAttribute("userId").toString());
            }

            Map<String, String> map = IPUtils.getOsAndBrowserInfo(request);
            String os = map.get("OS");
            String browser = map.get("BROWSER");
            String ip = IPUtils.getIpAddr(request);
            // 异步存储日志
            threadPoolTaskExecutor.execute(
                    new SysLogHandle(userId, ip, os, browser,
                            behavior.getBehavior(),
                            (Integer) result.get("moduleId"),
                            (String) result.get("otherData"), redisService, webVisitDao));
        }
    }
}
